package com.sunnada.weixin.util.weixinPay;

import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * 时间操作工具
 * @author yehui
 * @version V1.0 on 2014-3-20
 */
public class DateEasy implements Serializable {
	
	private static final long serialVersionUID = -4460041062580019056L;

	private SimpleDateFormat dfYYYYsMMsDD = null;

	private SimpleDateFormat dfYYsMMsDD = null;

	private SimpleDateFormat dfYYYYMMDD = null;

	private SimpleDateFormat dfYYMMDD = null;

	private SimpleDateFormat dfYYYYhMMhDD = null;

	private SimpleDateFormat dfYYhMMhDD = null;

	private SimpleDateFormat dfYYYYMMDDHHMMSS = null;

	private SimpleDateFormat dfYYYYsMMsDDsHHcMMcSS = null;
	private SimpleDateFormat dfYYYYcMMcDDcHHcMMcSS = null;

	private SimpleDateFormat dfYYYYsMMsDDsHHcMMcSSpSSS = null;

	private SimpleDateFormat dfHHcMMcSS = null;

	private SimpleDateFormat dfHHMMSS = null;

	private SimpleDateFormat dfMMsDD = null;
	private SimpleDateFormat dfYYYYMMDDHHMMSSSSS = null;

	private Date    date;
	private GregorianCalendar calendar =
			(GregorianCalendar)Calendar.getInstance();

	/**
	 * 获取14位的时间戳
	 */
	public static String char14Time() {
		return new DateEasy().toYYYYMMDDHHMMSS();
	}
	
	/**
	 * DateEasy with time now internally is generated.
	 */
	public DateEasy() {
		date = new Date();
		calendar.setTime(date);
	}

	/**
	 * DateEasy with specified time internally is generated. 
	 * @param source Specified time
	 */
	public DateEasy(DateEasy source) {
		this.date = source.date;
		calendar.setTime(this.date);
	}

	/**
	 * The specified character string is analyzed and DateEasy is generated.
	 * It corresponds to the following character strings.<br>
	 * �?2001/02/03<br>
	 * �?01/02/03<br>
	 * �?20010203<br>
	 * �?010203<br>
	 * �?2001-02-03<br>
	 * �?01-02-03<br>
	 * �?20010203151617<br>
	 * �?2001/02/03 15:16:17<br><br>
	 * There is "/" in the specified character string. <br>
	 *     1. At 11 digits or more  --->  [2001/02/03 15:16:17]<br>
	 *     2. At 9-10 digit         --->  [2001/02/03]<br>
	 *     3. At 8 digits or less   --->  [01/02/03]<br><br>
	 * There is "-" in the specified character string excluding the above-mentioned.<br>
	 *     1. At 9 digits or more   --->  [2001-02-03]<br>
	 *     2. At 8 digits or less   --->  [01-02-03]<br><br>
	 * Excluding the above-mentioned<br>
	 *     1. At 9 digits or more   --->  [20010203151617]<br>
	 *     2. At 7-8 digit          --->  [20010203]<br>
	 *     3. At 6 digits or less   --->  [010203]<br><br>
	 * @param dateStr Date character string
	 * @exception ParseException When failing in the analysis
	 */
	public DateEasy(String dateStr) throws ParseException {
		int length = dateStr.length();
		if (0 <= dateStr.indexOf('/')) {
			if (19 < length) {
				dfYYYYsMMsDDsHHcMMcSSpSSS = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
				date = dfYYYYsMMsDDsHHcMMcSSpSSS.parse(dateStr);
			}else if (10 < length) {
				dfYYYYsMMsDDsHHcMMcSS = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
				date = dfYYYYsMMsDDsHHcMMcSS.parse(dateStr);
			} else if (8 < length) {
				dfYYYYsMMsDD =	new SimpleDateFormat("yyyy/MM/dd");
				date = dfYYYYsMMsDD.parse(dateStr);
			} else {
				dfYYsMMsDD = new SimpleDateFormat("yy/MM/dd");
				date = dfYYsMMsDD.parse(dateStr);
			}
		} else if (0 <= dateStr.indexOf('-')) {
			if (8 < length) {
				dfYYYYhMMhDD = new SimpleDateFormat("yyyy-MM-dd");
				date = dfYYYYhMMhDD.parse(dateStr);
			} else {
				dfYYhMMhDD = new SimpleDateFormat("yy-MM-dd");
				date = dfYYhMMhDD.parse(dateStr);
			}
		} else {
			if (8 < length) {
				dfYYYYMMDDHHMMSS = new SimpleDateFormat("yyyyMMddHHmmss");
				date = dfYYYYMMDDHHMMSS.parse(dateStr);
			} else if (6 < length) {
				dfYYYYMMDD = new SimpleDateFormat("yyyyMMdd");
				date = dfYYYYMMDD.parse(dateStr);
			} else {
				dfYYMMDD = new SimpleDateFormat("yyMMdd");
				date = dfYYMMDD.parse(dateStr);
			}
		}
		calendar.setTime(date);
	}

	/**
	 * DateEasy with specified Date internally is generated. 
	 * @param date Date
	 */
	public DateEasy(Date date) {
		this.date = date;
		calendar.setTime(date);
	}

	/**
	 * DateEasy that shows at the time of the time millisecond from 1970/1/1 00:00:00 GMT is generated.
	 * @param time Millisecond from epoch
	 */
	public DateEasy(long time) {
		date = new Date(time);
		calendar.setTime(date);
	}


	/**
	 * The character string is acquired by the default format (2001/01/01). 
	 * @return Formatted character string
	 */
	public String toString() {
		return toYYYYsMMsDD();
	}

	/**
	 * The character string of 2001/01/01 forms is acquired.
	 * @return Formatted character string
	 */
	public String toYYYYsMMsDD() {
		if(dfYYYYsMMsDD == null){
			dfYYYYsMMsDD =	new SimpleDateFormat("yyyy/MM/dd");
		}
		return dfYYYYsMMsDD.format(date);
	}

	/**
	 * The character string of 01/01/01 forms is acquired.
	 * @return Formatted character string
	 */
	public String toYYsMMsDD() {
		if(dfYYsMMsDD == null){
			dfYYsMMsDD =	new SimpleDateFormat("yy/MM/dd");
		}
		return dfYYsMMsDD.format(date);
	}

	/**
	 * The character string of 20010101 forms is acquired. 
	 * @return Formatted character string
	 */
	public String toYYYYMMDD() {
		if(dfYYYYMMDD == null){
			dfYYYYMMDD =	new SimpleDateFormat("yyyyMMdd");
		}
		return dfYYYYMMDD.format(date);
	}

	/**
	 * The character string of 010101 forms is acquired.
	 * @return Formatted character string
	 */
	public String toYYMMDD() {
		if(dfYYMMDD == null){
			dfYYMMDD = new SimpleDateFormat("yyMMdd");
		}
		return dfYYMMDD.format(date);
	}

	/**
	 * The character string of 2001-01-01 forms is acquired.
	 * @return Formatted character string
	 */
	public String toYYYYhMMhDD() {
		if(dfYYYYhMMhDD == null){
			dfYYYYhMMhDD = new SimpleDateFormat("yyyy-MM-dd");
		}
		return dfYYYYhMMhDD.format(date);
	}

	/**
	 * The character string of 01-01-01 forms is acquired.
	 * @return Formatted character string
	 */
	public String toYYhMMhDD() {
		if(dfYYhMMhDD == null){
			dfYYhMMhDD = new SimpleDateFormat("yy-MM-dd");
		}
		return dfYYhMMhDD.format(date);
	}

	/**
	 * The character string of 20010101000000 forms is acquired.
	 * @return Formatted character string
	 */
	public String toYYYYMMDDHHMMSS() {
		if(dfYYYYMMDDHHMMSS == null){
			dfYYYYMMDDHHMMSS = new SimpleDateFormat("yyyyMMddHHmmss");
		}
		return dfYYYYMMDDHHMMSS.format(date);
	}

	/**
	 * The character string of 2001-01-01 00:00:00 form is acquired.
	 * @return Formatted character string
	 */
	public String toYYYYhMMhDDsHHcMMcSS() {
		if(dfYYYYsMMsDDsHHcMMcSS == null){
			dfYYYYsMMsDDsHHcMMcSS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		}
		return dfYYYYsMMsDDsHHcMMcSS.format(date);
	}
	
	/**
	 * The character string of 2001-01-01 00:00:00 form is acquired.
	 * @return Formatted character string
	 */
	public String toYYYYhMMhDDsHHcMMcSS(String split) {
		if(dfYYYYsMMsDDsHHcMMcSS == null){
			dfYYYYsMMsDDsHHcMMcSS = new SimpleDateFormat("yyyy-MM-dd"+split+"HH:mm:ss");
		}
		return dfYYYYsMMsDDsHHcMMcSS.format(date);
	}
	
	/**
	 * The character string of 2001年01月01日00时00分00秒 form is acquired.
	 * @param blank true:yyyy年MM月dd日 HH时mm分ss秒 false:yyyy年MM月dd日HH时mm分ss秒
	 * @return Formatted character string
	 */
	public String toYYYYcMMcDDcHHcMMcSS(boolean blank) {
		if(dfYYYYcMMcDDcHHcMMcSS == null){
			if (blank)
				dfYYYYcMMcDDcHHcMMcSS = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
			else 
				dfYYYYcMMcDDcHHcMMcSS = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
		}
		return dfYYYYcMMcDDcHHcMMcSS.format(date);
	}
	
	/**
	 * The character string of 2001/01/01 00:00:00 form is acquired.
	 * @return Formatted character string
	 */
	public String toYYYYsMMsDDsHHcMMcSS() {
		if(dfYYYYsMMsDDsHHcMMcSS == null){
			dfYYYYsMMsDDsHHcMMcSS = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		}
		return dfYYYYsMMsDDsHHcMMcSS.format(date);
	}

	/**
	 * The character string of the form is acquired at 00:00:00.
	 * @return Formatted character string
	 */
	public String toHHcMMcSS() {
		if(dfHHcMMcSS == null){
			dfHHcMMcSS = new SimpleDateFormat("HH:mm:ss");
		}
		return dfHHcMMcSS.format(date);
	}

	/**
	 * The character string of 000000 forms (second of the season) is acquired.
	 * @return Formatted character string
	 */
	public String toHHMMSS() {
		if(dfHHMMSS == null){
			dfHHMMSS = new SimpleDateFormat("HHmmss");
		}
		return dfHHMMSS.format(date);
	}

	/**
	 * The character string of 01/01 forms is acquired.
	 * @return Formatted character string
	 */
	public String toMMsDD() {
		if(dfMMsDD == null){
			dfMMsDD = new SimpleDateFormat("MM/dd");
		}
		return dfMMsDD.format(date);
	}

	/**
	 * It is judged whether this date exists since the specified date.
	 * @param when Date
	 * @return When it is not true when it is early so, this DateEasy object is false from the when object.
	 */
	public boolean before(DateEasy when) {
		return date.before(when.date);
	}

	/**
	 * 判断时间是否不在前面
	 * @param when
	 */
	public boolean notBefore(DateEasy when) {
		return !before(when);
	}
	
	/**
	 * It is judged whether this date exists since the specified date.
	 * @param when Date
	 * @return When it is not true when it is slow so, this DateEasy object is false from the when object.
	 */
	public boolean after(DateEasy when) {
		return date.after(when.date);
	}
	
	/**
	 * 判断时间是否不在后面
	 * @param when
	 */
	public boolean notAfter(DateEasy when) {
		return !after(when);
	}
	
	/**
	 * 判断时间是否相同
	 * @param when
	 * @return
	 */
	public boolean same(DateEasy when) {
		return date.compareTo(when.date) == 0;
	}
	
	/**
	 * 判断时间是否在指定区间内(包含)
	 * @param start
	 * @param end
	 */
	public boolean between(DateEasy start, DateEasy end) {
		return (date.compareTo(start.date) >= 0) && (date.compareTo(end.date) <= 0);
	}
	
	
	/**
	 * 判断时间是否在指定区间内(不包含)
	 * @param start
	 * @param end
	 */
	public boolean in(DateEasy start, DateEasy end) {
		return (date.compareTo(start.date) > 0) && (date.compareTo(end.date) < 0);
	}

	/**
	 * The year is acquired.
	 * The year of the point that this DateEasy shows is returned by four digits. 
	 * @return year of 4 digits
	 */
	public int getYear() {
		return calendar.get(Calendar.YEAR);
	}
	
	public String getYeara() {
        return (new SimpleDateFormat("yyyy")).format(date);
    }

	/**
	 * It judges at the leap year.
	 * It is judged whether year that this DateEasy shows is a leap year.
	 * @return For the leap year:true/When it is not so:false
	 */
	public boolean isLeapYear() {
		return calendar.isLeapYear(getYear());
	}

	/**
	 * It judges on February 29 at the leap year.
	 * It judges the day that this DateEasy shows is February 29 in the leap year.
	 * @return For an intercalary day:true/When it is not so:false
	 */
	public boolean isLeapDay() {
		return calendar.isLeapYear(getYear()) && getMonth()==2 && getDate()==29;
	}

	/**
	 * The month is acquired.
	 * The month of the point that this DateEasy shows is returned.
	 * @return month
	 */
	public int getMonth() {
		return calendar.get(Calendar.MONTH)+1;
	}

	/**
	 * The day is acquired.
	 * The day of the point that this DateEasy shows of month is returned.
	 * @return Day of month
	 */
	public int getDate() {
		return calendar.get(Calendar.DATE);
	}

	/**
	 * A day of the week is acquired.
	 * A day of the week of the point that this DateEasy shows is returned.
	 * It is returned by the value of the field of the Calendar class.
	 * @return A day of the week
	 * @see java.util.Calendar#SUNDAY
	 * @see java.util.Calendar#MONDAY
	 * @see java.util.Calendar#TUESDAY
	 * @see java.util.Calendar#WEDNESDAY
	 * @see java.util.Calendar#THURSDAY
	 * @see java.util.Calendar#FRIDAY
	 * @see java.util.Calendar#SATURDAY
	 */
	public int getDayOfWeek() {
		return calendar.get(Calendar.DAY_OF_WEEK);
	}
	
	public int getDayOfMonth() {
		return calendar.get(Calendar.DAY_OF_MONTH);
    }

	/**
	 * Hour is acquired.
	 * The hour of the point that this DateEasy shows is returned by the value of 24 time system.
	 * @return Value of 24 time system 0-23
	 */
	public int getHour() {
		return calendar.get(Calendar.HOUR_OF_DAY);
	}

	/**
	 * The minute is acquired. 
	 * The minute of the point that this DateEasy shows is returned.
	 * @return minute
	 */
	public int getMinute() {
		return calendar.get(Calendar.MINUTE);
	}

	/**
	 * The second is acquired.
	 * The second of the point that this DateEasy shows is returned.
	 * @return Second
	 */
	public int getSecond() {
		return calendar.get(Calendar.SECOND);
	}

	/**
	 * The millisecond is acquired.
	 * The millisecond of the point that this DateEasy shows is returned.
	 * @return millisecond
	 */
	public int getMilliSecond() {
		return calendar.get(Calendar.MILLISECOND);
	}

	/**
	 * The year is added.
	 * The year is advanced to the extent that specified. 
	 * The year returns before when the argument is a negative value.
	 * @param value Advanced years. Returning years in case of negative value.
	 */
	public DateEasy addYear(int value) {
		calendar.add(Calendar.YEAR, value);
		date = calendar.getTime();
		return this;
	}

	/**
	 * The month is added.
	 * The month is advanced to the extent that specified. 
	 * The month returns to the month of former when the argument is a negative value.
	 * @param value Advanced number of month. Returning number of month in case of negative value.
	 */
	public DateEasy addMonth(int value) {
		calendar.add(Calendar.MONTH, value);
		date = calendar.getTime();
		return this;
	}

	/**
	 * The day is added.
	 * The day is advanced to the extent that specified. 
	 * The day returns at the date before when the argument is a negative value. 
	 * The result will advance after next month when this object shows the end of the month.
	 * @param value Advanced days. Returning days in case of negative value.
	 */
	public DateEasy addDay(int value) {
		calendar.add(Calendar.DATE, value);
		date = calendar.getTime();
		return this;
	}

	/**    
	 * 减时间:天    
	 */
	public DateEasy minusDay(int day) {    
		calendar.setTime(this.toDate());      
		calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - day);
		date = calendar.getTime();
		return this;
	}
	
	/**
	 * 相差毫秒数
	 * @param when
	 */
	public long difference(DateEasy when){
		calendar.setTime(this.toDate());
		Calendar cal2 = Calendar.getInstance();
		cal2.setTime(when.toDate());
		long d = calendar.getTimeInMillis() - cal2.getTimeInMillis();
		return d >=0 ? d : -d;
	}
	
	/**
	 * 相差天数
	 * @param when
	 */
	public int dayDifference(DateEasy when){
		int days = new Long(difference(when) / (1000*60*60*24)).intValue();
		return days >=0 ? days : -days;
	}
	
	/**    
	 * 减时间:秒
	 */
	public DateEasy minusSecond(int second) {    
		calendar.setTime(this.toDate());      
		calendar.set(Calendar.SECOND, calendar.get(Calendar.SECOND) - second);
		date = calendar.getTime();
		return this;
	}

	/**
	 * The Date type data is acquired.
	 * @return Date data
	 */
	public Date toDate() {
		return date;
	}

	/**
	 * 1970/1/1 At 00:00:00 The number of milliseconds from GMT is returned.
	 * @return Millisecond
	 */
	public long getTime() {
		return date.getTime();
	}



	/**
	 * The character string of 2001 forms is acquired.
	 * @return Formatted character string
	 */
	public String toYYYY() {
		if(dfYYYYMMDD == null){
			dfYYYYMMDD = new SimpleDateFormat("yyyyMMdd");
		}
		return dfYYYYMMDD.format(date).substring(0,4);
	}

	/**
	 * [01]The character string of the form is acquired.
	 * @return Formatted character string
	 */
	public String toMM() {
		if(dfYYYYMMDD == null){
			dfYYYYMMDD =	new SimpleDateFormat("yyyyMMdd");
		}
		return dfYYYYMMDD.format(date).substring(4,6);
	}
	/**
	 * [01]The character string of the form is acquired.
	 * @return Formatted character string
	 */
	public String toDD() {
		if(dfYYYYMMDD == null){
			dfYYYYMMDD =	new SimpleDateFormat("yyyyMMdd");
		}
		return dfYYYYMMDD.format(date).substring(6,8);
	}

	/**
	 * The character string of 20010101000000000 forms is acquired.
	 * @return Formatted character string
	 */
	public String toYYYYMMDDHHMMSSSSS() {
		if(dfYYYYMMDDHHMMSSSSS == null){
			dfYYYYMMDDHHMMSSSSS =	new SimpleDateFormat("yyyyMMddHHmmssSSS");
		}
		return dfYYYYMMDDHHMMSSSSS.format(date);
	}

	/**
	 * The character string of 2001/01/01/ 00:00:00.000 forms is acquired.
	 * @return Formatted character string
	 */
	public String toYYYYsMMsDDbHHcMMcSSpSSS() {
		if(dfYYYYMMDDHHMMSSSSS == null){
			dfYYYYMMDDHHMMSSSSS =	new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
		}
		return dfYYYYMMDDHHMMSSSSS.format(date);
	}

	/**
	 * The character string of pattern forms is acquired.
	 * @param pattern
	 * @return Formatted character string
	 */
	public String format(String pattern) {
		return new SimpleDateFormat(pattern).format(date);
	}

	/**
	 * 时间计算 -- 
	 * 将毫秒数换算成x天x时x分x秒x毫秒
	 * @param ms
	 * @return
	 */
	public static String format(long ms) {
		int ss = 1000;
		int mi = ss * 60;
		int hh = mi * 60;
		int dd = hh * 24;

		long day = ms / dd;
		long hour = (ms - day * dd) / hh;
		long minute = (ms - day * dd - hour * hh) / mi;
		long second = (ms - day * dd - hour * hh - minute * mi) / ss;
		long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;
		String strDay = day < 10 ? "0" + day : "" + day;
		System.out.println("milliSecond==>"+milliSecond);
		String strHour = hour < 10 ? "0" + hour : "" + hour;
		String strMinute = minute < 10 ? "0" + minute : "" + minute;
		String strSecond = second < 10 ? "0" + second : "" + second;
		String strMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;
		strMilliSecond = milliSecond < 100 ? "0" + strMilliSecond : "" + strMilliSecond;

		return strDay + "天" + strHour + "时" + strMinute + "分" + strSecond + "秒" + strMilliSecond+"毫秒";

	}



}

// ----- End Of File -----
